package tue.cse.advanceddatabases.project;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.faces.context.FacesContext;

import org.apache.commons.httpclient.NameValuePair;
import org.dom4j.Element;

import tue.cse.advanceddatabases.project.xml.album.Album;
import tue.cse.advanceddatabases.project.xml.album.AlbumsParser;
import tue.cse.advanceddatabases.project.xml.artist.Artist;
import tue.cse.advanceddatabases.project.xml.artist.ArtistsParser;
import tue.cse.advanceddatabases.project.xml.genre.Genre;
import tue.cse.advanceddatabases.project.xml.genre.GenreParser;

public class ArtistEngineBean extends MusicEngineBean {
	
	private String artistToSearch;
	private Logger logger = Logger.getLogger(ArtistEngineBean.class.getName());
	private List<Artist> artists;
	private String artist;
	
	//Goran
	private Artist _artist = new Artist();
		
	/*
	 * public properties for private properties
	 */
	
	//Goran
	public Artist getDefaultArtist(){
	  	return _artist;
	}
	
	public String getArtistToSearch() {
		return artistToSearch;
	}

	public void setArtistToSearch(String artistToSearch) {
		this.artistToSearch = artistToSearch;
	}
	
	/** return albums for "albumToSearch" **/
	public List<Artist> getArtists(){
		return artists;
	}
	
	/** return current artist searched by id **/
	public Artist getArtist(){
		
		String artistKey = getArtistKey();
		
		String artist = searchArtistId(artistKey);
		
		if (artist != null){
			List<Element> artistsElement = removeExistDBElement(artist);
			if (artistsElement!=null){
				logger.info("ArtistsElement are contained in" + artistsElement);
				return ArtistsParser.parse(artistsElement).get(0);
			}
		}
		
		return null;
	}
	
	
	/*
	 * Actions: public methods (query constructions)
	 */
	
	/** search albums by "artistToSearch" property **/
	public void searchArtists(){
		artists = null;
		logger.info("Searching artists by Name");
		
		NameValuePair[] parameters = new NameValuePair[2];
		parameters[0] = new NameValuePair("name",artistToSearch);
		parameters[1] = new NameValuePair("order","rating-count");
		
		String result = executeQueryXQL("artistsQueryByName.xql",parameters);
		
		
		if (result != null){
			Element artistsElement = stringToXml(result);
			if (artistsElement!=null){
				logger.info("Artists are contained in" + artistsElement);
				artists = ArtistsParser.parse(artistsElement);
				return;
			}			
		}
		
		artists = null;
	}
	
	/** search albums by "artistKey" parameter **/
	public String searchArtistId(String artistKey){
		
		logger.info(" Search Artist ID:" + artistKey);
		artist = null;
		String query = queryBegin() + artistIdQuery(artistKey) + queryEnd();
		String result = executeQuery(query,"Artists.xml");
		
		if (!("fail".equalsIgnoreCase(result)))
			return result;

		return null;
		
	}
	
	public List<Artist> getTopRatedArtistsRelated(){
		logger.info("Searching for getTopRatedArtistsRelated");
		String albumId = getAlbumKey();
		String artistId = getArtist().getId();
		
		NameValuePair[] parameters = new NameValuePair[2];
		parameters[0] = new NameValuePair("artistId",artistId);
		parameters[1] = new NameValuePair("count","4");
		
		String result = executeQueryXQL("topRatedArtistsRelated.xql",parameters);
		
		
		if (result != null){
			Element artistsElement = stringToXml(result);
			if (artistsElement!=null){
				logger.info("Artists are contained in" + artistsElement);
				return ArtistsParser.parse(artistsElement);
			}			
		}
		
		return null;
	}
	
	/** Access the manageArtists page with cleared values **/
	public String accessAddArtist(){
	   Clear();
	   return "manageArtist";
	}
	
	/** go to edit Artist by "artistKey" parameter **/
	public String editArtist(){
    	    	this._artist = getArtist();
    	    	setIsNew(false);
    	    	return "manageArtist";
	}
	
	/** remove Artist by "artistKey" parameter **/
	public void removeArtist(){
    	    if (deleteArtist(getArtistKey())){
    	        searchArtists();
                status = "Item deleted.";
            }
            else{
                status = "Error while deleting!";
            }	
	}
	
	/** add genre **/
	public void addGenre(){
	  	logger.info("Inserting Genre");
	     
	  	String command = getInsertGenreForArtistCommand(getDefaultArtist().getId(), getDefaultArtist().getGenre());
		
	  	String query = updateBegin() + command + updateEnd();
	  	String result = executeQuery(query, "Artists.xml");
		
	  	logger.info("Inserting result is:" + result);
	}
	
	/** remove Artist by "artistKey" parameter **/
	public void removeGenre(){
	        FacesContext facesContext = FacesContext.getCurrentInstance();
		String genre = (String) facesContext.getExternalContext().getRequestParameterMap().get("genreKey");
    	    	
		logger.info("Deleting Artist");
		     
		String command = getDeleteGenreCommand(getDefaultArtist().getId(), genre);
			
		String query = updateBegin() + command + updateEnd();
		String result = executeQuery(query, "Artists.xml");
			
		logger.info("Deleting result is:" + result);
	}
	
	public List<Genre> getGenresByArtist(){
	  	logger.info(" Get Genres for Artist ID: " + getDefaultArtist().getId());
		
		String query = queryBegin() + getAllGenresCommand(getDefaultArtist().getId()) + queryEnd();
		String result = executeQuery(query,"Artists.xml");
		
		if (result != null){
		  	List<Element> genresElement = removeExistDBElement(result);
			if (genresElement!= null){
				logger.info("Genres are contained in" + genresElement);
				return GenreParser.parse(genresElement);
			}
		}

		return null;
	}
	//Goran
	public void btnSave(){
	  
              if (getIsNew()){
                  if (insertArtist()){
                      status = "Item saved.";
                  }
                  else{
                      status = "Error while saving!";
                  }
              }
              else{
                  if (updateArtist()){
                      status = "Item saved.";
                  }
                  else{
                    	status = "Error while saving!";
                  }
              }
	}
	
	//Goran
	public void btnDelete(){
	  
	    if (deleteArtist(getDefaultArtist().getId())){
                SetupForm();
                status = "Item deleted.";
            }
            else{
                status = "Error while deleting!";
            }
	}
	
	//Goran
	public void btnNew(){
	     SetupForm();    
	}
	
	/*
	 * Private Query constructions
	 */
	
	/** Clear values that are used in the bean **/
	private void Clear()
	{   
	    _artist = new Artist();
	    setIsNew(true);
	}
	
	private void SetupForm()
	{
	    Clear();
	    status = "";
	}
	
	//Goran
	private boolean insertArtist(){
	     
	     logger.info("Inserting Artist");

	    //TODO: generate artistId
	     _artist.setId(_artist.getName());
	     
	     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	     String dateEntered = sdf.format(new Date());
	     
	     String command = getInsertArtistCommand(getDefaultArtist().getId(), getDefaultArtist().getName(),getDefaultArtist().getImage(),  
		 getDefaultArtist().getDescription(), getDefaultArtist().getUrl(), dateEntered);
		
	     String query = updateBegin() + command + updateEnd();
	     String result = executeQuery(query, "Artists.xml");
		
	     logger.info("Inserting result is:" + result);
	  
	     if (!("fail".equalsIgnoreCase(result))){
	       	  setIsNew(false);	
		  return true;
	     }
	     return false;
	}
	
	//Goran
	private boolean updateArtist(){
	   
	     logger.info("Updating Artist");

	     String command = getUpdateArtistCommand(getDefaultArtist().getId(), getDefaultArtist().getName(), getDefaultArtist().getImage(),
		 getDefaultArtist().getDescription(), getDefaultArtist().getUrl());
		
	     String query = updateBegin() + command + updateEnd();
	     String result = executeQuery(query, "Artists.xml");
		
	     logger.info("Inserting result is:" + result);
	     
	     if (!("fail".equalsIgnoreCase(result))){
	       	  setIsNew(false);	
		  return true;
	     }
	     return false;
	}
	
	//Goran
	private boolean deleteArtist(String artistId){
	  
	     logger.info("Deleting Artist");
	     
	     String command = getDeleteArtistCommand(artistId);
		
	     String query = updateBegin() + command + updateEnd();
	     String result = executeQuery(query, "Artists.xml");
		
	     logger.info("Deleting result is:" + result);
		
	     if (!("fail".equalsIgnoreCase(result))){
	       	  setIsNew(false);	
		  return true;
	     }
	     return false;
	}
	
	/*
	 * Queries
	 */
	
	/** artist id query **/
	private String artistIdQuery(String $artistId){
		return "element { \"artists\" }{ " +
			"for $artist in //artist " +
			"where $artist/@id =\"" + $artistId + "\" " + 
			"return $artist" +
			"}";
	}
	
	/** insert artist command **/
	private String getInsertArtistCommand(String artistId, String name, String image, 
	    String description, String url, String dateEntered){
		return "<xu:append select=\"/artists\">" + 
				"<xu:element name=\"artist\">" +
				"<xu:attribute name=\"id\">" + artistId + "</xu:attribute>" +
				"<name>" + name + "</name>" +
				"<image>" + image + "</image>" +
				"<description>" + description + "</description>" +
				"<url>" + url + "</url>" + 
				"<genres></genres>" +
				"<date_created>" + dateEntered + "</date_created>" +
				"<rating>0</rating>" +
				"<rating-count>0</rating-count>" +
				"<comment-count>0</comment-count>" +
				"</xu:element></xu:append>";
	}
	
	/** update artist command **/
	private String getUpdateArtistCommand(String artistId, String name, String image, 
	    String description, String url){
		return "<xu:update select=\"/artists/artist[@id=\'" + artistId + "\']/name\">" +
		            name +
		       "</xu:update>" +
		       "<xu:update select=\"/artists/artist[@id=\'" + artistId + "\']/image\">" +
		            image +
		       "</xu:update>" +
		       "<xu:update select=\"/artists/artist[@id=\'" + artistId + "\']/description\">" +
		       	    description +
		       "</xu:update>" +
		       "<xu:update select=\"/artists/artist[@id=\'" + artistId + "\']/url\">" +
		            url +
		       "</xu:update>";
	}
	
	/** delete artist (and comments for that artist) command **/
	private String getDeleteArtistCommand(String artistId){
		return "<xu:remove select=\"/artists/artist[@id = \'" + artistId + "\']\" />" +
		       "<xu:remove select=\"/comments/comment[music_id = \'" + artistId + "\']\" />";
	}	
	
	/** insert genre for artist command **/
	private String getInsertGenreForArtistCommand(String artistId, String genre){
	  	return "<xu:append select=\"/artists/artist[@id=\'" + artistId + "\']/genres\">" + 
	  		"<xu:element name=\"genre\">" + genre +
	  		"</xu:element></xu:append>";
	}
	
	/** delete genre for artist command **/
	private String getDeleteGenreCommand(String artistId, String genre){
		return "<xu:remove select=\"/artists/artist[@id = \'" + artistId + "\']/genres/genre[text() = \'" + genre + "\']\" />";
	}	
	
	/** get all artist genres command **/
	private String getAllGenresCommand(String artistId){
	  	return "element { \"artists\" }{ " +
	  		"for $artist in //artist " +
	  		"where $artist/@id =\"" + artistId + "\" " +
	  		"return for $genre in $artist/genres/genre " + 
	  		        "return $genre" +
	  		"}";
	}
}
